# -*- coding: utf-8 -*-

"""
@author: Laowang
@contact: QQ:1125564921
@Created on: 2022/6/21
@Remark: 
"""

from typing import List
from collections import defaultdict

from .xt_api_cfg import XTPlatConfig
from .xt_utils import auth_require_, public_request_, sign_encrypt_data

from framework_strategy.gopy.base import GateWay
from framework_strategy.gopy.gateways.utils import (
    RequestParamterObj,
    auth_require,
    public_request,
    ResponseKlineObj,
    ResponseTickerObj,
    ResponseOrderBookObj,
    ResponseTradesObj,
    ResponseBalanceObj,
    ResponseOrderObj,
    ResponseOrdersObj,
    ResponseCancelOrderObj,
    ResponseAccountOrderObj,
    ResponseMineOrdersObj
)
from framework_strategy.gopy.base.constant import *


def server_time_response(data, parameter=None):
    """ server time response """
    if not data:
        return data
    # print("[server_time_response] ", data)
    ndata = dict()
    ndata["data"] = data["data"]["serverTime"]
    return ndata


@public_request(key=public_request_, response_handle=server_time_response)
def get_server_time(self, event) -> RequestParamterObj:
    """ Get server time now """
    # print("--get_server_time--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_SERVER, event)


@public_request(key=public_request_, response_handle=None)
def get_account(self, event) -> RequestParamterObj:
    """ Get account info """
    # print("--get_account--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_ACCOUNT, event)


def market_config_response(data, parameter=None):
    """ account response """
    # print("[account_response] ", data).
    if not data:
        return data

    ndata = dict()
    for k, v in data.items():
        ndata[k] = {
            "minMoney": v["minMoney"],
            "quotePrecision": v["pricePoint"],
            "quoteAssetPrecision": v["coinPoint"]
        }
    return {"data": ndata}


@public_request(key=public_request_, response_handle=market_config_response)
def get_all_market_config(self, event) -> RequestParamterObj:
    """ Access all market config """
    # print("--get_all_market_config--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_MARKET_CONFIG, event)


def kline_response(data, parameter=None):
    """ kline response """

    if not data.get("datas"):
        return data

    ndata = defaultdict(list)
    for d in data["datas"]:
        ndata["data"].append(
            ResponseKlineObj(
                d[0],
                d[1],
                d[2],
                d[3],
                d[4],
                d[5],
            )
        )
    return ndata


@public_request(key=public_request_, response_handle=kline_response)
def get_klines(self, event) -> RequestParamterObj:
    """ Get Klines """
    # print("--get_klines--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_KLINE, event)


def ticker_response(data, parameter=None):
    """ ticker response """
    if not data:
        return data

    ndata = dict()
    ndata["data"] = ResponseTickerObj(
        data["bid"],
        0,
        data["ask"],
        0,
        data["price"],
    )
    return ndata


@public_request(key=public_request_, response_handle=ticker_response)
def get_ticker(self, event) -> RequestParamterObj:
    """ Aggregate market """
    # print("--get_ticker--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_TICKER, event)


def tickers_response(data, parameter=None):
    """ tickers response """

    if not data:
        return data

    ndata = dict()

    for k, v in data.items():
        ndata[k] = ResponseTickerObj(
            v["bid"],
            0,
            v["ask"],
            0,
            v["price"],
        )
    return {"data": ndata}


@public_request(key=public_request_, response_handle=tickers_response)
def get_tickers(self, event) -> RequestParamterObj:
    """ All aggregate market """
    # print("--get_tickers--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_TICKERS, event)


def depth_response(data, parameter=None):
    """ depth response """
    if not data:
        return data

    ndata = dict()
    ndata["data"] = ResponseOrderBookObj(data["asks"], data["bids"])
    return ndata


@public_request(key=public_request_, response_handle=depth_response)
def get_depth(self, event) -> RequestParamterObj:
    """ Gain market depth """
    # print("--get_depth--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_DEPTH, event)


def trades_response(data, parameter=None):
    """ trades response """
    # TODO 接口未走通
    if not data:
        return data
    ndata = defaultdict(list)
    for d in data:
        ndata["data"].append(ResponseTradesObj())
    return ndata


@auth_require(key=auth_require_, response_handle=trades_response)
def get_trades(self, event) -> RequestParamterObj:
    """ Get trade history """
    # print("--get_trades--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_TRADES, event)


def balance_response(data, parameter=None):
    """ balance response """

    if not data:
        return data
    ndata = defaultdict(list)
    for k, v in data["data"].items():
        ndata["data"].append(
            ResponseBalanceObj(
                k,
                v["available"],
                v["freeze"]
            )
        )
    return ndata


@auth_require(key=auth_require_, response_handle=balance_response)
def get_balance(self, event) -> RequestParamterObj:
    """ Get account balance """
    # print("--get_balance--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_BALANCE, event)


def fund_response(data, parameter=None):
    """ fund response """
    if not data:
        return data
    ndata = defaultdict(list)
    for k, v in data["data"].items():
        ndata["data"].append(
            ResponseBalanceObj(
                k,
                v["available"],
                v["freeze"]
            )
        )
    return ndata


@auth_require(key=auth_require_, response_handle=fund_response)
def get_fund(self, event) -> RequestParamterObj:
    """ Gets the corresponding information for an account """
    # print("--get_fund--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_FUNDS, event)


def send_order_response(data, parameter=None):
    """ order response """
    if not data:
        return data
    ndata = dict()
    ndata["data"] = ResponseOrderObj(
        data["data"].get("id") or 0,
        parameter.data.event_data.market,
        parameter.data.event_data.type,
        parameter.data.event_data.price,
        parameter.data.event_data.number
    )
    return ndata


@auth_require(key=auth_require_, response_handle=send_order_response)
def send_order(self, event) -> RequestParamterObj:
    """ Order """
    # print("--send_order--", self, event)
    return RequestParamterObj("POST", XTPlatConfig.SEND_ORDER, event)


def send_orders_response(data, parameter=None):
    """ orders response """
    if not data:
        return data

    ndata = defaultdict(list)
    for d in data["data"]:
        ndata["data"].append(ResponseOrdersObj(
            d["amount"],
            d["price"],
            d["id"],
            d["type"]
        ))
    return ndata


@auth_require(key=auth_require_, response_handle=send_orders_response)
def send_orders(self, event) -> RequestParamterObj:
    """ Orders """
    # print("--send_orders--", self, event)
    event.event_data.data = sign_encrypt_data(event.event_data.data)

    return RequestParamterObj("POST", XTPlatConfig.BATCH_ORDER, event)


def cancel_order_response(data, parameter=None):
    """ cancel order response """

    if not data:
        return data

    res = ResponseCancelOrderObj(
        data["data"]["id"],
        data["info"]
    )
    return {"data": res}


@auth_require(key=auth_require_, response_handle=cancel_order_response)
def cancel_order(self, event) -> RequestParamterObj:
    """ Cancel order """
    # print("--cancel_order--", self, event)
    return RequestParamterObj("POST", XTPlatConfig.CANCEL_ORDER, event)


def cancel_orders_response(data, parameter=None):
    """ cancels order response """
    if not data:
        return data

    ndata = defaultdict(list)
    for d in data["data"]:
        ndata["data"].append(
            ResponseCancelOrderObj(d["id"], d["msg"])
        )
    return ndata


@auth_require(key=auth_require_, response_handle=cancel_orders_response)
def cancel_orders(self, event) -> RequestParamterObj:
    """ Cancel orders """
    # print("--cancel_orders--", self, event)
    event.event_data.data = sign_encrypt_data(event.event_data.data)

    return RequestParamterObj("POST", XTPlatConfig.BATCH_CANCEL, event)


def get_order_response(data, parameter=None):
    """ get order response """
    if not data:
        return data

    data = data["data"]
    res = ResponseAccountOrderObj(
        data["number"],
        data["price"],
        data["id"],
        data["status"],
        data["type"],
        data["entrustType"],
    )
    return {"data": res}


@auth_require(key=auth_require_, response_handle=get_order_response)
def get_order(self, event) -> RequestParamterObj:
    """ Get order """
    # print("--get_order--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_ORDER, event)


def open_order_response(data, parameter=None):
    """ open order response """

    if not data:
        return data

    ndata = defaultdict(list)
    for d in data["data"]:
        ndata["data"].append(
            ResponseAccountOrderObj(
                d["number"],
                d["price"],
                d["id"],
                d["status"],
                d["type"],
                d["entrustType"],
            )
        )
    return ndata


@auth_require(key=auth_require_, response_handle=open_order_response)
def get_open_order(self, event) -> RequestParamterObj:
    """ Obtain outstanding orders """
    # print("--get_open_order--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_OPEN_ORDERS, event)


def orders_response(data, parameter=None):
    """ orders response """
    if not data:
        return data

    ndata = defaultdict(list)
    for d in data["data"]:
        ndata["data"].append(
            ResponseAccountOrderObj(
                d["number"],
                d["price"],
                d["id"],
                d["status"],
                d["type"],
                d["entrustType"],
            )
        )
    return ndata


@auth_require(key=auth_require_, response_handle=orders_response)
def get_orders(self, event) -> RequestParamterObj:
    """ Obtain all orders information"""
    # print("--get_orders--", self, event)
    event.event_data.data = sign_encrypt_data(event.event_data.data)
    return RequestParamterObj("GET", XTPlatConfig.GET_BATCH_ORDERS, event)


def mine_trades_response(data, parameter=None):
    """ mine trades """
    if not data:
        return data
    ndata = defaultdict(list)

    for d in data["data"]:
        ndata["data"].append(ResponseMineOrdersObj(
            d["orderId"],
            d["time"],
            d["price"],
            d["amount"],
            d["value"],
            d["type"],
            d["entrustType"],
            d["fee"],
            d["takerMaker"],
        ))
    return ndata


@auth_require(key=auth_require_, response_handle=mine_trades_response)
def get_mine_trades(self, event) -> RequestParamterObj:
    # print("--get_mine_trades--", self, event)
    return RequestParamterObj("GET", XTPlatConfig.GET_ACCOUNT_TRADES, event)


class XTGateway(GateWay):

    exchanges = ["XT"]
    def __init__(self, main_engine, event_engine, gateway_name = "XT", proxy=None) -> None:
        super().__init__(main_engine, event_engine, gateway_name, proxy)

    ON_EVENT: List = [
        (XT_EVENT_SERVERTIMES, get_server_time),
        (XT_EVENT_ACCOUNT, get_account),
        (XT_EVENT_MARKETCONFIG, get_all_market_config),
        (XT_EVENT_KLINE, get_klines),
        (XT_EVENT_TICKER, get_ticker),
        (XT_EVENT_TICKERS, get_tickers),
        (XT_EVENT_MARKETDEPTH, get_depth),
        (XT_EVENT_ORDER_TRADE, get_trades),
        (XT_EVENT_ACCOUNT_BALANCE, get_balance),
        (XT_EVENT_ACCOUNT_FUND, get_fund),
        (XT_EVENT_SENDORDER, send_order),
        (XT_EVENT_SENDORDERS, send_orders),
        (XT_EVENT_CANCELORDER, cancel_order),
        (XT_EVENT_CANCELORDERS, cancel_orders),
        (XT_EVENT_ORDER_STATUS, get_order),
        (XT_EVENT_OPENORDER, get_open_order),
        (XT_EVENT_ORDERS_STATUS, get_orders),
        (XT_EVENT_ACCOUNT_MINE_TRADES, get_mine_trades),
    ]
